//
// Copyright (c) 2005 BroadVision, Inc. All rights reserved.
//
// This software is copyrighted.  Under the copyright laws, this software
// may not be copied, in whole or in part, without prior written consent
// of BroadVision, Inc. or its assignees.  This software is provided under
// the terms of a license between BroadVision and the recipient, and its
// use is subject to the terms of that license.
//
// This software may be protected by one or more U.S. and International
// patents.  Certain applications of BroadVision One-To-One software are
// covered by U.S. patent 5,710,887.
//
// TRADEMARKS: BroadVision and BroadVision One-To-One are registered
// trademarks of BroadVision, Inc., in the United States and the European
// Community, and are trademarks of BroadVision, Inc., in other
// countries.  The BroadVision logo, is a trademark of BroadVision, Inc.,
// in the United States and other countries. Additionally, IONA and Orbix
// are trademarks of IONA Technologies, Ltd.  RSA, MD5, and RC2 are
// trademarks of RSA Data Security, Inc.
//

package com.broadvision.manage.common.tools.action.group;

import java.util.*;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.struts.action.ActionForm;
import org.apache.struts.action.ActionForward;
import org.apache.struts.action.ActionMapping;
import org.apache.struts.Globals;

import com.broadvision.system.accesscontrol.client.*;
import com.broadvision.system.accesscontrol.exceptions.AccessControlException;
import com.broadvision.visitor.client.VisitorManager;
import com.broadvision.visitor.client.Visitor;
import com.broadvision.visitor.client.VisitorGroupManager;
import com.broadvision.visitor.exceptions.VisitorGroupException;
import com.broadvision.visitor.interfaces.VisitorGroup;
import com.broadvision.portal.services.OrganizationObjectInfo;

import com.broadvision.manage.tools.action.BaseAction;
import com.broadvision.manage.common.tools.action.user.UserUtils;
import com.broadvision.manage.common.tools.user.UserProfile;

/**
 * Saves a group's data to database.
 */
public class GroupSaveAction extends BaseAction {

  public static final VisitorManager visitorMgr = new VisitorManager();

  /**
   * Implements the action for saving a group.
   * <p> <p>
   * @param mapping <code>ActionMapping</code> object used to select this instance
   * @param form Optional <code>ActionForm</code> bean for this request (if any)
   * @param request <code>HttpServletRequest</code> object to process
   * @param response <code>HttpServletResponse</code> object to process
   * <p> <p>
   * @return <code>ActionForward</code> instance describing where and how
   * control should be forwarded, or null if the response has already been completed
   * <p> <p>
   * @throws Exception if an error occurs
   */
  public ActionForward processExecute(ActionMapping mapping,
                                      ActionForm form,
                                      HttpServletRequest request,
                                      HttpServletResponse response)
                               throws Exception
  {
    try {
      boolean edit = ((Boolean) UserUtils.getP(form, "edit")).booleanValue();
      String groupFQN = (String) UserUtils.getP(form, "groupFQN");
      String originalGroupFQN = (String) UserUtils.getP(form, "originalGroupFQN");
      String groupName = ((String) UserUtils.getP(form, "groupName")).trim();
      String[] administrators = (String[]) UserUtils.getP(form, "administrators");
      VisitorGroup thisGroup = VisitorGroupManager.getVisitorGroupByFqn(groupFQN);
      HashMap parentAdminMap = this.getParentAdministerators(thisGroup);
      String subGroupFQN = null;
      boolean isLDAP = false;
      if (groupFQN.indexOf("=") > -1) {
        // LDAP 
        isLDAP = true;
        if (edit) {
          subGroupFQN = groupName;
        }
        else {
          String pathN = extractPathName(groupFQN);  
          int ind = groupFQN.indexOf(":");
          String groupContext = groupFQN.substring(0, ind);
          subGroupFQN = groupContext + ":cn=" + groupName + "," + pathN;
        }
      }
      else {
        subGroupFQN = groupFQN + "/" + groupName;
      }
      OrganizationObjectInfo org = null;
      AccessManager aclMgr = AccessManager.instance();
      VisitorGroup oldGroup = null;
      if (!UserUtils.isEmptyString(originalGroupFQN)) {
        oldGroup = VisitorGroupManager.getVisitorGroupByFqn(originalGroupFQN);
      }
      if ((edit) && (originalGroupFQN.equalsIgnoreCase(subGroupFQN))) {
        // no change to the group name
        org = new OrganizationObjectInfo(oldGroup);
        ArrayList admins = (ArrayList) aclMgr.getPrincipalsInRole("OrganizationAdmin", org);
        if (null != admins) {
          for (int i = 0; i < admins.size(); i++) {
            Visitor v = (Visitor) admins.get(i);
            aclMgr.revokeRole(v, "OrganizationAdmin", org);
          }
        }
        if (isLDAP) {
          request.setAttribute("_groupFQN", UserUtils.getP(form, "parentGroupFQN"));
        }
      }
      else {
        // there are changes to group name or we are creating a new group
        if (edit) {
          // change name change: do not delete the existing one and create a new one
          // instead rename the group
          if ("root".equals(groupFQN)) {
            request.setAttribute(Globals.ERROR_KEY, "error.application");
            return mapping.findForward("failure");
          }
          else if (!UserUtils.isEmptyString(groupFQN)) {
            oldGroup.rename(groupName);
          }
        }
        else {
          // create a new subgroup
          List subGroups = new ArrayList();
          subGroups.add(groupName);
          try {
            thisGroup.createSubGroups(subGroups);
          }
          catch (Exception dEx) {
            request.setAttribute(Globals.ERROR_KEY, "error.group.save.dup");
            return mapping.findForward("error");
          }
        }
        // get the new visitor group
        VisitorGroup subG = VisitorGroupManager.getVisitorGroupByFqn(subGroupFQN);
        org = new OrganizationObjectInfo(subG);	      
      }
      if (null != administrators) {
        for (int i = 0; i < administrators.length; i++) {
          if (parentAdminMap.containsKey(administrators[i]) == true) {
            continue;
          }
          Visitor theVisitor = visitorMgr.getVisitor(administrators[i]);
          aclMgr.grantRole(theVisitor, "OrganizationAdmin", org);
        }
      }
    }
    catch (Exception ex) {
      request.setAttribute(Globals.ERROR_KEY, "error.application");
      return mapping.findForward("failure");
    }
    // change made to support groups by service 
    String parentGroupFQN = (String) UserUtils.getP(form, "parentGroupFQN");
    if ("root".equals(parentGroupFQN)) { 
      request.setAttribute("_groupFQN", parentGroupFQN);
    }
    return mapping.findForward("success");
  }
  
  private String extractPathName(String fqn) {
    int i = fqn.indexOf(":");
    if (i < 0) {
      return fqn;
    }
    else {
      return fqn.substring(i + 1);
    }
  }

  protected HashMap getParentAdministerators(VisitorGroup thisGroup) {
    HashMap adminMap = new HashMap();
    AccessManager aclMgr = null;
    List parentGroupList = new ArrayList(1);
    parentGroupList.add(thisGroup);
    try {
      List thisGroupParents = thisGroup.getParents(true);
      if (thisGroupParents != null) {
        parentGroupList.addAll(thisGroupParents);
      }
      aclMgr = AccessManager.instance();
    }
    catch (VisitorGroupException ex) {
      ;
    }
    catch (AccessControlException ex) {
      ;
    }
    for (int i = parentGroupList.size() - 1; i >= 0; i--) {
      VisitorGroup oneVisitorGroup = (VisitorGroup)parentGroupList.get(i);
      OrganizationObjectInfo oneOrgOI = new OrganizationObjectInfo(oneVisitorGroup);
      ArrayList oneOrgOIAdmins = null;
      try {
        oneOrgOIAdmins = (ArrayList)aclMgr.getPrincipalsInRole(UserProfile.ORGANIZATION_ADMIN, oneOrgOI);
      }
      catch (AccessControlException ex) {
        ;
      }
      if (oneOrgOIAdmins != null && oneOrgOIAdmins.isEmpty() == false) {
        for (int j = 0; j < oneOrgOIAdmins.size(); j++) {
          Visitor oneVisitor = (Visitor)oneOrgOIAdmins.get(j);
          adminMap.put(oneVisitor.getUserAlias(), oneVisitor);
        }
      }
    }
    return adminMap;
  }

}
